package com.millstein.tsinglog.service.impl;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.millstein.tsinglog.commons.constant.SystemConstant;
import com.millstein.tsinglog.commons.enums.ResultCode;
import com.millstein.tsinglog.config.AliyunConfig;
import com.millstein.tsinglog.config.UploadProperties;
import com.millstein.tsinglog.exception.TsinglogException;
import com.millstein.tsinglog.filter.ThumbnailsImgFilter;
import com.millstein.tsinglog.utils.MyUtils;
import com.millstein.tsinglog.service.UploadService;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
@EnableConfigurationProperties(value = {UploadProperties.class, AliyunConfig.class})
public class UploadServiceImpl implements UploadService {

    @Autowired
    private UploadProperties uploadProperties;

    @Autowired
    private AliyunConfig aliyunConfig;

    @Override
    public Map<String, Object> uploadImage(MultipartFile file) {
        // 1.校验文件
        if ((double) file.getSize() / 1024 / 1024 > SystemConstant.MAX_SIZE_OF_UPLOAD) {
            throw new TsinglogException(ResultCode.FILE_TOO_BIG);
        }

        Map<String, Object> map = new HashMap<String, Object>();

        // 获取源文件的名称
        String oFileName = file.getOriginalFilename();
        // 获取源文件的后缀名
        String oExt = oFileName.substring(oFileName.lastIndexOf('.') + 1);
        // 检查后缀名是否被允许
        if (!uploadProperties.getAllowedPicTypes().contains(oExt)) { // 检查不通过
            throw new TsinglogException(ResultCode.INVALID_FILE_TYPE);
        }
        BufferedImage image;
        try {
            // 校验上传文件的类型正确，但是内容不是图片
            image = ImageIO.read(file.getInputStream());
            if(image == null) { // 如果不是图片就报错
                throw new TsinglogException(ResultCode.INVALID_FILE_CONTENT);
            }
        } catch (IOException e) {
            log.error("上传的文件格式异常");
            throw new TsinglogException(ResultCode.UPLOAD_FAILURE);
        }

        // 2.压缩文件
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        OSS ossClient = null;
        try {
            // 计算压缩比例。这里的逻辑是如果图片的宽度小于700，那么就不缩放；大于700，则缩放到700
            Double compressRatio = image.getWidth() >= 700D ? ((double) 700/image.getWidth()): 1D;
            if (oExt.equals("png")) { // 是png图片要先转为jpg图片
                Thumbnails.of(file.getInputStream())
                        .scale(compressRatio)
                        .addFilter(new ThumbnailsImgFilter())
                        .outputFormat("jpg")
                        .toOutputStream(baos);
            } else {
                Thumbnails.of(file.getInputStream())
                        .scale(compressRatio)
                        .toOutputStream(baos);
            }
        } catch (IOException e) {
            log.error("图片压缩失败");
            throw new TsinglogException(ResultCode.COMPRESS_FAILURE);
        }

        // 3.处理上传的文件命名，命名格式为“一级目录/二级目录/文件名”
        String fileName = MyUtils.genUUID() + ".jpg";
        String wholeName =
                aliyunConfig.getBasePackage() + "/" + fileName.charAt(0) + "/" + fileName.charAt(1) + "/" + fileName;

        // 4.上传到阿里云
        try {
            ossClient = new OSSClientBuilder().build(aliyunConfig.getEndPoint(),
                    aliyunConfig.getKeyId(), aliyunConfig.getKeySecret());
            ossClient.putObject(aliyunConfig.getBucketName(), wholeName, new ByteArrayInputStream(baos.toByteArray()));
            map.put("imgUrl", wholeName);
            System.out.println(wholeName);
        } catch (Exception e) {
            log.error("保存文件时出现异常");
            throw new TsinglogException(ResultCode.UPLOAD_FAILURE);
        } finally {
            ossClient.shutdown();
        }

        return map;
    }
}
